#include "OSProc.h"
#include "structure.h"
//#include "OutPut.h"
#include "PAL.h"
#include "length.h"


#define ROOT             (NOW->root)
#define SWAProot         (FindStream("SWAP",ROOT))

#define TIMES 				(0xFF800000u)

//The Platform Code layer
extern "C"
{
  //  extern void TaskSchedule(_ptlong MARK);
  
  extern void __SVC_SYS_STACK_SCHEDULE(unsigned int*,unsigned int*);
  extern void __IRQ_SYS_STACK_SCHEDULE(unsigned int*,unsigned int*);

  extern void __IRQ_ISR_JUMP(void (*fun)(void));
  
  extern void __SetFPBaseAddr(unsigned int);

  extern _ptlong __GET_DFSR();
  extern _ptlong __GET_IFSR();
  extern _ptlong __GET_DFAR();
  extern _ptlong __GET_IFAR();

}


extern unsigned int const api_vecTbl[];
using namespace PAL;
using namespace MM;

static int _SaveMemory(_ptlong* phyAddr,_length offset)
{
  _str buff = CreateStream([]()->_str{return NULL;});
  MMUMemoryMap(NOW,phyAddr,buff);
  int ret =  DelegateToThread(ConvertToPrv(buff,SWAProot,0,offset));
  MMUMemorySet(NOW,buff,PAGE_UNALLOCATED);
  EndStream(buff);
  return ret;

}
static int _RecoverMemory(_ptlong* phyAddr,_length offset)
{
  _str buff = CreateStream([]()->_str{return NULL;});
  MMUMemoryMap(NOW,phyAddr,buff);
  int ret =  DelegateToThread(ConvertToPub(SWAProot,buff,0,offset));
  MMUMemorySet(NOW,buff,PAGE_UNALLOCATED);
  EndStream(buff);
  return ret; 
}
static int _CopyMemory(_ptlong* phyAddr,_length offset)
{
  _str buff = CreateStream([]()->_str{return NULL;});
  MMUMemoryMap(NOW,phyAddr,buff);
  _Memcpy(buff,_GetAddress(offset),PAGE_SIZE);
  MMUMemorySet(NOW,buff,PAGE_UNALLOCATED);
  EndStream(buff);
  return 1;
}



static int __MemoryAbortSVR(_pcb* swapoutp,_ptlong* swapout,_pcb* swapinp,_ptlong* swapin,_ptlong phyAddr,
			    int (*_ActivateM)
			    (
			     _pcb*/*swapin*/,_ptlong*/*swapin*/,
			     int(*/*SaveMemory*/)(_ptlong*,_length),
			     int(*/*RecoverMemory*/)(_ptlong*,_length),
			     int(*/*CheckMemory*/)(_ptlong*,_length)
			     ))
{
  _ptlong swapout_state = MMUGetState(swapoutp->flPage,swapout);
  _ptlong swapin_state  = MMUGetState(swapinp->flPage,swapin);
  _ActivateM(swapoutp,swapout,
	     (swapout_state & PAGE_COW
	      ? ([](_ptlong* phyAddr,_length offset)->int
		{
		  CopyOnWrite_Swapout(_GetProcess(offset),_GetAddress(offset));
		  return _SaveMemory(phyAddr,offset);
		})
	      : (swapout_state & PAGE_NORMAL
		 ? _SaveMemory
		 : NULL)),
	     (swapin_state & PAGE_SWAPOUT
	      ? (swapin_state & PAGE_COW
		 ? ([](_ptlong* phyAddr,_length offset)->int
		   {
		     CopyOnWrite_Swapin(_GetProcess(offset),_GetAddress(offset));
		     return _RecoverMemory(phyAddr,offset);
		   })
		 : _RecoverMemory)
	      :(swapin_state & PAGE_COW
		? _CopyMemory
		: NULL)),
	     [](_pcb* pro,_ptlong* vMem){return MMUGetPMem(pro,vMem);});
    
    
}





extern "C"
{
  //MemoryAbort Service
  int MemoryAbortSVR()
  {
    //TODO:MemoryAbortService
    //Get Data Register or Instruction Register
    
  }
  inline int _MemoryAbortSVR(_ptlong state,_ptlong addr)
  {
    if(ActivateMemory(NOW,addr,__MemoryAbortSVR) != NULL)
      return 1;
  }

  //Interrupt Service
  void InterruptSVR(unsigned int IntNum,unsigned int* _stack_pointer)
  {/* Used To called ROSEIRQHandler*/
  //Now it's only support the Threadturning Service
    //Save the contest
    if(IntNum == SYS_ISR_TURN)
      {
	ROSEThreadTurning(_stack_pointer);
      }
	else
	  {
	    MUTEX_LOCK(&(ISRLocker));
	    void (*fun)(void) = ISR[IntNum];
	    __IRQ_ISR_JUMP(fun);
	    MUTEX_UNLOCK(&(ISRLocker));
	  }
    
		
  }
  //Thread Turning
  //Auto Thread Turning
  void AutoThreadTurning(unsigned int* _stack_pointer)
  {
    //Most register,except r11~r14
    TaskStackSave(_stack_pointer,(u32*)&(((_tcb*)run->content)->stack));
    unsigned int* nextStack = &(((_tcb*)(run->next->content))->stack.r13);
    unsigned int* orgStack  = &(((_tcb*)(run->content))->stack.r13);
    __IRQ_SYS_STACK_SCHEDULE(orgStack,nextStack);
    run = run->next;
    __SetFPBaseAddr((unsigned int)(NOWT->init_argv[0]));	//the flPage will be saved in the argv[0]
    
    TaskStackOut(_stack_pointer,(u32*)&(((_tcb*)run->content)->stack));//There are maybe  no problems. I am not sure 
  }
  
  //Syscall Thread Turning
  void SyscallThreadTurning(unsigned int MARK,unsigned int* _stack_pointer)
  {/*Used To called as ROSESVCTT*/
    //Most register,except r11~r14
    TaskStackSave(_stack_pointer,(u32*)&(((_tcb*)run->content)->stack));
    
	unsigned int* nextStack = &(((_tcb*)(run->next->content))->stack.r13);
	unsigned int* orgStack  = &(((_tcb*)(run->content))->stack.r13);
	__SVC_SYS_STACK_SCHEDULE(orgStack,nextStack);
	if(MARK == SCHEDULE_DEFAULT)
	  {
	    run = run->next;
	  }
	else if(MARK == SCHEDULE_MUTEX)
	  {
	    ring* this = run;
	    RingRemove(this);
	    run = run->next;
	  }
	else if(MARK == SCHEDULE_END)
	  {//Thread Terminate		
	    ring* this = run;
	    run = run->next;
	    
	    //Deal with it
	    //TODO:...
			_ThreadTerminate(this->content);
			RingRemove(this);
			_KHEAPRELEA(this);
			
	  }
	else if(MARK == SCHEDULE_PROCESS_END)		//no use?
	  {//MainThread Terminate	
	    _tcb* target = run->content;
		target = target->pPro->mthread;	
		
		ring* this = run;
		run = run->next;
		while( ((_tcb*)(run->content))->pPro == target->pPro)	//init thread will ensure that no dead cycle
		  run = run->next;
		//Deal with it
		//TODO:...
		_ThreadTerminate(target);
		RingRemove(this);
		_KHEAPRELEA(this);
		
	  }
	__SetFPBaseAddr((unsigned int)(NOWT->init_argv[0]));	//the flPage will be saved in the argv[0]
	INVALIDATE_ALL_TLB();
	
	TaskStackOut(_stack_pointer,(u32*)&(((_tcb*)run->content)->stack));//There are maybe  no problems. I am not sure 
  }
  

  
  
}


